﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ClientApp
{
    public partial class ChatClientForm : Form
    {
        public ChatClientForm()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
        }



        //与服务器的连接  
        TcpClient tcpClient;
        //与服务器数据交互的流通道  
        private NetworkStream Stream;
        //客户端的状态  
        private static string CLOSED = "closed";
        private static string CONNECTED = "connected";
        //定义当前客户的状态  
        private string state = CLOSED;

        private bool stopFlag;
        private Color color;

        #region 点击“登陆”
        private void btnLogin_Click(object sender, System.EventArgs e)
        {
            if (state == CONNECTED)
            {
                MessageBox.Show("已经登陆", "提示信息");
                return;
            }
            if (this.tbUserName.Text.Length == 0)
            {
                MessageBox.Show("请输入您的昵称", "提示信息");
                this.tbUserName.Focus();
                return;
            }
            try
            {
                // Client clients = new Client();  
                //创建一个客户端套接字，他是logion的一个套接字，将被传递给ChatClient窗体  
                tcpClient = new TcpClient();
                //向指定的IP地址服务器发送连接请求  
                tcpClient.Connect(IPAddress.Parse(txtHost.Text), Int32.Parse(txtport.Text));
                //获得与服务器数据交互的流通道  
                Stream = tcpClient.GetStream();
                //启动一个新的线程，执行方法this.ServerResponse(),  
                //以便来响应从服务器发回的信息  
                Thread thread = new Thread(new ThreadStart(this.ServeerResponse));
                thread.Start();
                //向服务器发送"CONN"请求命令，此命令的格式与服务器的定义的格式一致  
                //命令格式为：命令标示符CONN| 发送者的名字  
                string cmd = "CONN|" + this.tbUserName.Text + "|";
                //将字符串转化为字符数组  
                Byte[] outbytes = System.Text.Encoding.Default.GetBytes(cmd.ToCharArray());
                Stream.Write(outbytes, 0, outbytes.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 点击“发送”按钮
        private void btnSend_Click(object sender, System.EventArgs e)
        {
            try
            {
                if (!this.cbPrivate.Checked)
                {
                    //此时命令的格式是：  
                    //命令标示符（CHAT）|发送者的名字|发送内容  
                    string message = "CHAT|" + this.tbUserName.Text + "|" + tbSendContent.Text + "|";
                    tbSendContent.Text = "";
                    tbSendContent.Focus();
                    //将字符串转为字符数组  
                    Byte[] outbytes = System.Text.Encoding.Default.GetBytes(message.ToCharArray());
                    Stream.Write(outbytes, 0, outbytes.Length);
                }
                else
                {
                    if (lstUsers.SelectedIndex == -1)
                    {
                        MessageBox.Show("请在一个列表中选择一个用户", "提示信息");
                        return;
                    }
                    string receiver = lstUsers.SelectedItem.ToString();
                    //命令标示符(PRIV|)|发送者的名字|接收者的用户名|发送内容  
                    string message = "PRIV|" + this.tbUserName.Text + "|" + receiver + "|" + tbSendContent.Text + "|";
                    tbSendContent.Text = "";
                    tbSendContent.Focus();
                    //将字符串转化为字符数组  
                    byte[] outbytes = System.Text.Encoding.ASCII.GetBytes(message.ToCharArray());
                    Stream.Write(outbytes, 0, outbytes.Length);
                }
            }
            catch (Exception ex)
            {
                this.rtbMsg.AppendText("网络发生错误");
            }
        }
        #endregion

        #region 用于接收服务器发回的信息
        //根据不同的命令，执行相应的操作  
        private void ServeerResponse()
        {
            //定义一个 byte数组，用于接收从服务器发回的信息  
            //每次所能接收的数据包的最大长度为1024个字符  
            byte[] buff = new byte[1024];
            string msg = "";
            int len;
            try
            {
                if (!Stream.CanRead)
                {
                    return;
                }
                stopFlag = false;
                while (!stopFlag)
                {
                    //从流中得到数据，并存入到buff字符数组中  
                    len = Stream.Read(buff, 0, buff.Length);
                    if (len < 1)
                    {
                        Thread.Sleep(200);
                        continue;
                    }
                    //将字符数组转化为字符串  
                    msg = System.Text.Encoding.Default.GetString(buff, 0, len);
                    msg.Trim();
                    string[] tokens = msg.Split(new Char[] { '|' });
                    //tokens = msg.Split(new Char[] { '|' });//takens[0]中保存了命令标识符(LIST或JOIN或QUIT)  
                    if (tokens[0].ToUpper() == "OK")
                    {
                        //处理响应  
                        add("命令执行成功");
                    }
                    else if (tokens[0].ToUpper() == "ERR")
                    {
                        //命令执行错误  
                        add("命令执行错误:" + tokens[1]);
                    }
                    else if (tokens[0] == "LIST")
                    {
                        //此时从服务器返回的消息格式：  
                        //命令标志符(LIST|用户名|用户名2|用户名3...  
                        //跟新在线用户列表  
                        lstUsers.Items.Clear();
                        for (int i = 1; i < tokens.Length - 1; i++)
                        {
                            lstUsers.Items.Add(tokens[i].Trim());
                        }
                    }
                    else if (tokens[0] == "JOIN")
                    {
                        //此时从服务器返回的消息格式  
                        add(tokens[1] + "" + "已经进入了聊天室");
                        SetControlList(lstUsers, tokens[1]);
                        // this.lstUsers.Items.Add(tokens[1]);  
                        if (this.tbUserName.Text == tokens[1])
                        {
                            this.state = CONNECTED;
                        }
                    }
                    else if (tokens[0] == "QUIT")
                    {
                        if (this.lstUsers.Items.IndexOf(tokens[1]) > -1)
                        {
                            //this.lstUsers.Items.Remove(tokens[1]);  
                            RemoveListboxItem(lstUsers, tokens[1]);
                        }
                        add("用户：" + tokens[1] + "已经离开");
                        state = CLOSED;
                    }
                    else
                    {
                        //如果从服务器返回的其他消息格式  
                        //则在listBox控件中直接现实  
                        add(msg);
                    }

                }
                //关闭连接  
                tcpClient.Close();
            }
            catch (Exception ex)
            {
                add("网络发生错误");
            }
        }
        #endregion

        #region 点击“离开”按钮
        private void btnExit_Click(object sender, System.EventArgs e)
        {
            if (state == CONNECTED)
            {
                string message = "EXIT|" + this.tbUserName.Text + "|";
                //将字符串转化为字符数组  
                Byte[] outbytes = System.Text.Encoding.Default.GetBytes(message.ToCharArray());
                Stream.Write(outbytes, 0, outbytes.Length);

                this.state = CLOSED;
                this.stopFlag = true;
                this.lstUsers.Items.Clear();
            }
        }
        #endregion

        #region 点击"关闭"
        private void btnClose_Click(object sender, EventArgs e)
        {
            btnExit_Click(sender, e);
        }
        #endregion

        #region 获取颜色的方法
        private void btnColor_Click(object sender, EventArgs e)
        {
            ColorDialog colorDialog1 = new ColorDialog();
            colorDialog1.Color = this.rtbMsg.SelectionColor;
            if (colorDialog1.ShowDialog() == DialogResult.OK && colorDialog1.Color != this.rtbMsg.SelectionColor)
            {
                this.rtbMsg.SelectionColor = colorDialog1.Color;
                color = colorDialog1.Color;
            }
        }
        #endregion

        #region 添加信息
        private void add(string msg)
        {
            if (!color.IsEmpty)
            {
                SetControlText(rtbMsg, color.ToString());
                // this.rtbMsg.SelectionColor = color;  
            }
            SetControlText(rtbMsg, msg + "\n");
            //this.rtbMsg.SelectedText = msg + "\n";  
        }
        #endregion

        #region 定义一个委托
        private delegate void SetControlTextDelegate(Control control, string txt);
        //判断当前控件是否在此线程中，当是此线程时，调用该线程  
        //如果不是同一线程，让其回调  
        private void SetControlText(Control control, string txt)
        {
            if (control.InvokeRequired)
            {
                var d = new SetControlTextDelegate(SetControlText);
                BeginInvoke(d, new object[] { control, txt });
            }
            else
            {
                control.Text = txt;
            }
        }

        private delegate void SetControlListDelegate(ListBox listbox, string txt);
        //判断当前控件是否在此线程中，当是此线程时，调用该线程  
        //如果不是同一线程，让其回调  
        private void SetControlList(ListBox listbox, string item)
        {
            if (listbox.InvokeRequired)
            {
                var d = new SetControlListDelegate(SetControlList);
                BeginInvoke(d, new object[] { listbox, item });
            }
            else
            {
                listbox.Items.Add(item);
            }
        }

        private void RemoveListboxItem(ListBox listbox, string item)
        {
            if (listbox.InvokeRequired)
            {
                var d = new SetControlListDelegate(RemoveListboxItem);
                BeginInvoke(d, new object[] { listbox, item });
            }
            else
            {
                if (listbox.Items.Contains(item))
                    listbox.Items.Remove(item);
            }
        }

        #endregion 

        private void ChatClientForm_Load(object sender, EventArgs e)
        {

        }


    }
}
